/*
 * Copyright (c) 2010 Frederic Daoud
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.fdaoud.rayures.quickstart;

import java.io.*;
import java.util.*;
import java.util.jar.*;

/**
 * Main class for Rayures-Quickstart.
 *
 * @author Frederic Daoud
 */
public class Rayures {
  private static SimpleTemplateEngine templateEngine = new SimpleTemplateEngine();
  private static Map<String, Object> map = new HashMap<String, Object>();
  private static final String SEP = "/";

  private static final String TEMPLATE_PATH = "templates" + SEP;
  private static final String TEMPLATE_PATH_RAYURES = TEMPLATE_PATH + "rayures" + SEP;
  private static final String SRC_MAIN_JAVA = "src" + SEP + "main" + SEP + "java" + SEP;

  private static final String[] PLACEHOLDER_EXTENSIONS = {
    "css",
  };

  private static JarFile jarFile;
  private static List<JarEntry> jarFileEntries = new ArrayList<JarEntry>();

  public static void main(String[] args) throws Exception {
    System.out.println();
    System.out.println("Welcome to Rayures!");
    System.out.println();
    System.out.println("A Maven project will be generated to get you started.");
    System.out.println();

    String jarFileName = System.getProperty("java.class.path");
    jarFile = new JarFile(new File(jarFileName));
    Enumeration<JarEntry> enumeration = jarFile.entries(); 
    while (enumeration.hasMoreElements()) { 
      JarEntry entry = enumeration.nextElement(); 
      String path = entry.getName(); 
      if (!entry.isDirectory() && path.startsWith(TEMPLATE_PATH)) { 
        jarFileEntries.add(entry);
      } 
    } 

    String appName = "";
    String basePackage = "";
    String ctxPath = "";

    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
    String input = "";

    System.out.println("First, enter the name of your application.");
    System.out.println("This should not have any spaces, as in 'hello'.");
    System.out.println("You can separate words likeThis or like-this or even like_this.");
    System.out.println();

    // TODO: refactor this
    while (appName.length() == 0) {
      System.out.print("Name of your application: ");
      input = stdin.readLine().trim();
      appName = input;
    }

    System.out.println();
    System.out.println("Next, enter the name of your base package.");
    System.out.println("This should be a valid Java package, as in 'com.example'.");
    System.out.println();

    while (basePackage.length() == 0) {
      System.out.print("Base package: ");
      input = stdin.readLine().trim();
      basePackage = input;
    }

    System.out.println();
    System.out.println("Next, enter the web application's context path.");
    System.out.println("This will make the URL look like http://localhost:8080/<Context path>");
    System.out.println();

    while (ctxPath.length() == 0) {
      System.out.print("Context path: ");
      input = stdin.readLine().trim();
      ctxPath = input;
    }

    map.put("appName", appName);
    map.put("groupId", basePackage);
    map.put("artifactId", appName);
    map.put("basePackage", basePackage);
    map.put("ctxPath", ctxPath);

    createApp(TEMPLATE_PATH_RAYURES, appName, basePackage);

    System.out.println();
    System.out.println("Created " + appName + ".");
    System.out.println("You can run it with these commands:");
    System.out.println();
    System.out.println("cd " + appName);
    System.out.println("mvn tomcat:run");
    System.out.println();
    System.out.println("Enjoy Stripes and Rayures!");
  }

  private static void createApp(String rootPath, String appName, String basePackage) throws Exception {
    String target = "." + SEP + appName;
    String dynamicPath = SRC_MAIN_JAVA + basePackage.replaceAll("\\.", "/");

    // Static paths / files
    String staticFileRoot = rootPath + "static_path" + SEP + "files" + SEP;
    for (JarEntry entry : findFiles(staticFileRoot)) {
      String name = entry.getName().substring(staticFileRoot.length());
      copyFile(entry, target + SEP + name);
    }
    
    // Static paths / templates
    String staticTemplateRoot = rootPath + "static_path" + SEP + "templates";
    for (JarEntry entry : findFiles(staticTemplateRoot)) {
      String name = entry.getName().substring(staticTemplateRoot.length());
      processTemplate(jarFile.getInputStream(entry), target + SEP + name);
    }
    
    // Dynamic paths / files
    String dynamicFileRoot = rootPath + "dynamic_path" + SEP + "files";
    for (JarEntry entry : findFiles(dynamicFileRoot)) {
      String name = entry.getName().substring(dynamicFileRoot.length());
      copyFile(entry, target + SEP + dynamicPath + SEP + name);
    }

    // Dynamic paths / templates
    String dynamicTemplateRoot = rootPath + "dynamic_path" + SEP + "templates";
    for (JarEntry entry : findFiles(dynamicTemplateRoot)) {
      String name = entry.getName().substring(dynamicTemplateRoot.length());
      processTemplate(jarFile.getInputStream(entry), target + SEP + dynamicPath + SEP + name);
    }

    // Placeholder files
    for (String ext : PLACEHOLDER_EXTENSIONS) {
      String path = target + SEP + "src" + SEP + "main" + SEP + "webapp" + SEP + ext;
      mkdirs(path);
      BufferedWriter placeHolderFile = new BufferedWriter(
        new FileWriter(path + SEP + appName + "." + ext + ""));
      placeHolderFile.write("/* " + appName + "." + ext + " */");
      placeHolderFile.newLine();
      placeHolderFile.write("/* Add your code here */");
      placeHolderFile.newLine();
      placeHolderFile.flush();
      placeHolderFile.close();
    }
  }

  private static void processTemplate(InputStream inputStream, String dest) throws Exception {
    mkdirs(dest);
    Writer writer = new FileWriter(dest);
    templateEngine.write(inputStream, map, writer);
    writer.flush();
    writer.close();
  }

  private static void copyFile(JarEntry entry, String dest) throws Exception {
    mkdirs(dest);
    InputStream in = jarFile.getInputStream(entry);
    OutputStream out = new FileOutputStream(dest);
    byte[] buffer = new byte[1024];
    int length;
    while ((length = in.read(buffer)) > 0) {
      out.write(buffer, 0, length);
    }
    out.close();
    in.close();
  }

  private static List<JarEntry> findFiles(String rootPath) {
    List<JarEntry> found = new ArrayList<JarEntry>();
    for (JarEntry entry : jarFileEntries) {
      if (entry.getName().startsWith(rootPath)) {
        found.add(entry);
      }
    }
    return found;
  }

  private static void mkdirs(String file) {
    new File(file.substring(0, file.lastIndexOf(SEP))).mkdirs();
  }
}
